﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using KingTools.CommonsHelper.Constants;
using KingTools.SocketHelper.Model;

namespace KingTools.SocketHelper
{
    /// <summary>
    ///     连接 Socket 代理
    /// </summary>
    public delegate void BeginAceptHandler(SendUtils sendData);

    /// <summary>
    ///     消息代理
    /// </summary>
    /// <param name="strTemp"></param>
    public delegate void MessageHandler(string strTemp);

    /// <summary>
    ///     异步 Socket 处理类
    /// </summary>
    public class AsySocketUtils
    {
        private readonly IPEndPoint iep;

        /// <summary>
        ///     消息代理处理器
        /// </summary>
        private readonly MessageHandler message;

        private string IP;
        private string Port;
        private IAsyncResult result;
        private Socket socket;

        public AsySocketUtils(string IP, string Port, MessageHandler message)
        {
            this.message = message;
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            iep = new IPEndPoint(IPAddress.Parse(IP), int.Parse(Port));
        }

        /// <summary>
        ///     Socket 初始化
        /// </summary>
        /// <param name="IP">IP</param>
        /// <param name="Port">Port</param>
        /// <param name="verifyBytes">验证 byte[]</param>
        /// <param name="loginBytes">登录 byte[]</param>
        /// <param name="businessBytes">业务 byte[]</param>
        public void BeginAccept(SendUtils sendData)
        {
            try
            {
                if (Constants.RECONNECTION)
                {
                    if (socket != null)
                    {
                        if (socket.Connected)
                        {
                            socket.Close();
                        }
                    }
                    Constants.RECONNECTION = false;
                }

                if (!socket.Connected)
                {
                    Constants.isConnect = true;
                    Constants.isVerify = true;
                    Constants.isLogin = true;
                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    result = socket.BeginConnect(iep, ConnectCallback, socket);
                    result.AsyncWaitHandle.WaitOne();
                    message("连接成功！");
                }
            }
            catch (Exception e)
            {
                message("连接异常！");
            }

            if (Constants.isConnect)
            {
                SendLogin(socket, sendData);
                Receive(socket);
                SendBusiness(socket, sendData);
            }
            else
            {
                SendBusiness(socket, sendData);
            }

            Receive(socket);

            //socket.Shutdown(SocketShutdown.Both);
            //socket.Close();
        }

        /// <summary>
        ///     连接后回调
        /// </summary>
        /// <param name="ar"></param>
        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                var client = (Socket) ar.AsyncState;
                client.EndConnect(ar);
                message("Socket connected to " + client.RemoteEndPoint + "\n");
            }
            catch (Exception e)
            {
                message("连接异常！");
            }
        }

        private void SendLogin(Socket client, SendUtils sendData)
        {
            try
            {
                if (Constants.isVerify)
                {
                    Constants.isVerify = false;
                    byte[] verifyBytes = sendData.SendVerifyProtocol();
                    // 发送 Netty 验证
                    client.BeginSend(verifyBytes, 0, verifyBytes.Length, 0, SendCallback, client);
                    message("发送 Netty 验证成功！");
                    Thread.Sleep(1000);
                }

                if (Constants.isLogin)
                {
                    Constants.isLogin = false;
                    byte[] loginBytes = sendData.SendLoginProtocol();

                    // 发送登录协议验证
                    client.BeginSend(loginBytes, 0, loginBytes.Length, 0, SendCallback, client);
                    message("发送 登录 协议成功！");
                    Constants.isConnect = false;
                }
            }
            catch
            {
                Constants.isConnect = true;
                Constants.isVerify = true;
                Constants.isLogin = true;
                message("登录时异常！");
            }
        }

        /// <summary>
        ///     发送 Socket 数据
        /// </summary>
        /// <param name="client">socket 对象</param>
        /// <param name="verifyBytes">Netty 验证 byte[]</param>
        /// <param name="loginBytes">登录验证 byte[]</param>
        /// <param name="businessBytes">业务 byte[]</param>
        private void SendBusiness(Socket client, SendUtils sendData)
        {
            try
            {
                byte[] businessBytes = sendData.SendBusinessProtocol();
                // 发送业务协议
                client.BeginSend(businessBytes, 0, businessBytes.Length, 0, SendCallback, client);
                message("发送业务协议成功！");
            }
            catch (Exception e)
            {
                message("发送业务协议数据异常！");
            }
        }

        /// <summary>
        ///     发送数据后回调
        /// </summary>
        /// <param name="ar"></param>
        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                var client = (Socket) ar.AsyncState;
                int bytesSend = client.EndSend(ar);
                message("Send " + bytesSend + "bytes to server.\n");
            }
            catch (Exception e)
            {
                message("发送数据异常！");
            }
        }

        /// <summary>
        ///     接收服务端发送数据
        /// </summary>
        /// <param name="client"></param>
        private void Receive(Socket client)
        {
            try
            {
                var state = new StateObject();
                state.workSocket = client;
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state);
            }
            catch (Exception e)
            {
                message("接收数据异常！");
            }
        }

        /// <summary>
        ///     接收数据回调
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                var state = (StateObject) ar.AsyncState;
                Socket client = state.workSocket;
                int bytesRead = client.EndReceive(ar);
                if (Constants.encryptKey == null)
                {
                    Constants.encryptKey = new byte[8];
                    int j = 0;
                    for (int i = 10; i <= 17; i++)
                    {
                        Constants.encryptKey[j++] = state.buffer[i];
                    }
                }

                if (bytesRead > 0)
                {
                    state.sb.Append(Encoding.Default.GetString(state.buffer, 0, bytesRead));
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, ReceiveCallback,
                                        state);
                }
                else
                {
                    if (state.sb.Length > 1)
                    {
                        string response = state.sb.ToString();
                        message("retrun message : " + response + "\n");
                    }
                }
            }
            catch (Exception e)
            {
                message("接收数据异常！");
            }
        }
    }
}